Functional interfaces in Java 8
A functional interface in Java is an interface that contains exactly one abstract method. Functional interfaces are key to enabling functional programming in Java, especially with the introduction of lambda expressions in Java 8. These interfaces can be implemented by any class or lambda expression that provides a concrete implementation of the single abstract method.
Key Characteristics of a Functional Interface:
- Single Abstract Method (SAM):A functional interface contains only one abstract method. This method defines the functionality that the interface represents.
- @FunctionalInterface Annotation (Optional):Although optional, it's a good practice to annotate your functional interface with @FunctionalInterface. This annotation tells the compiler to enforce the rule of having only one abstract method in the interface. If you try to add a second abstract method, the compiler will throw an error.
Example of a Functional Interface:
@FunctionalInterface
public interface MyFunctionalInterface {
void execute(); // Single abstract method
}
You can implement this interface in a traditional way by creating a class or by using a lambda expression, which is more concise:
// Traditional implementation
public class MyClass implements MyFunctionalInterface {
@Override
public void execute() {
System.out.println("Executing...");
}
}
// Usage with lambda expression
MyFunctionalInterface func = () -> System.out.println("Executing...");
func.execute();
Built-in Functional Interfaces in Java:
Java 8 introduced several functional interfaces in the java.util.function package. Some commonly used functional interfaces are:
- Predicate:Represents a boolean-valued function that takes one argument.
- Method: boolean test(T t)
- Example
Predicate isPositive = (num) -> num > 0;
- Function:Represents a function that accepts one argument and produces a result.
- Method: R apply(T t)
- Example
Function stringLength = (str) -> str.length();
- Consumer:Represents an operation that accepts a single input argument and returns no result.
- Method: void accept(T t)
- Example
Consumer printString = (str) -> System.out.println(str);
- Supplier:Represents a function that supplies a result without taking any input.
- Method: T get()
- Example
Supplier randomValue = () -> Math.random();
- BiFunction:Represents a function that takes two arguments and produces a result.
- Method: R apply(T t, U u)
- Example
BiFunction add = (a, b) -> a + b;
Lambda Expressions and Functional Interfaces:
Functional interfaces are typically used with lambda expressions, which are a concise way of expressing instances of single-method interfaces. For example:
// Lambda expression for a functional interface
MyFunctionalInterface myFunc = () -> System.out.println("Lambda execution");
myFunc.execute();
Lambda expressions allow you to implement the abstract method of a functional interface without needing to write a full class.
Practical Use Cases:
- Streams API:Functional interfaces are heavily used in the Streams API for operations like filtering, mapping, and reducing data.
- Event Handling:Functional interfaces can be used to handle events in a more concise manner.
- Callbacks:Functional interfaces can be used to define callback mechanisms where you need to pass behavior as an argument.
Summary:
- A functional interface contains exactly one abstract method.
- It can be used with lambda expressions or method references to implement functionality in a concise way.
- Java provides many built-in functional interfaces in the java.util.function package, which are commonly used in modern Java programming, especially with streams and collections.
The concept of functional interfaces is central to making Java more functional and concise, especially in the context of modern APIs and concurrent programming.